﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Nollie.Storage.Memory;
using Nollie.Storage.Database;
using Nollie.CacheTypes.Database;
using Nollie.CacheTypes.Mixed;
using Nollie.CacheTypes.Memory;

namespace Nollie.CacheTypes
{
	public class Partition : IPartition
	{
		private IDatabaseStorage _databaseCache;
		private MemoryStorage _memoryCache;
		private string _partitionName;
		private ICache _cache;
		private bool _useMemCache;
		private bool _useDbCache;

		public ICache Cache
		{
			get;
			private set;
		}

		public Partition(ICache cache, IDatabaseStorage databaseCache, string partitionName, PartitionTypes cacheType, int memCacheCapacity)
		{
			_cache = cache;
			_databaseCache = databaseCache;
			_partitionName = partitionName;

			if (cacheType == PartitionTypes.Db
				|| cacheType == PartitionTypes.Mixed)
				_useDbCache = true;

			if (cacheType == PartitionTypes.Mem
				|| cacheType == PartitionTypes.Mixed)
				_useMemCache = true;

			if (_useMemCache)
				_memoryCache = new MemoryStorage(memCacheCapacity);
		}
		public void Add(CacheItem item)
		{
			item.Validate();

			if (_useMemCache)
				_memoryCache.Add(item);

			if (_useDbCache)
				_databaseCache.Add(_partitionName, item);
		}
		public void Add(string key, object value, TagList tags, DateTime expiryDate)
		{
			var item = new CacheItem(key, value, tags, expiryDate);

			Add(item);
		}
		public T Get<T>(string key)
		{
			CacheItem cacheItem = null;

			if (_useMemCache)
				cacheItem = _memoryCache.Get(key);

			if (cacheItem == null
				&& _useDbCache)
				cacheItem = _databaseCache.Get(_partitionName, key);
			
			if (cacheItem == null)
				return default(T);

			if (cacheItem.IsExpired())
			{
				if (_useMemCache)
					_memoryCache.RemoveByCacheKey(cacheItem.Key);

				return default(T);
			}

			if (_useMemCache)
				_memoryCache.Add(cacheItem);

			return (T) cacheItem.Value;
		}
		public void RemoveByCacheKey(string key)
		{
			if (_useMemCache)
				_memoryCache.RemoveByCacheKey(key);
			
			if (_useDbCache)
				_databaseCache.RemoveByCacheKey(_partitionName, key);
		}
		public void RemoveByTag(string key)
		{
			if (_useMemCache)
				_memoryCache.RemoveByTag(key);
			
			if (_useDbCache)
				_databaseCache.RemoveByTag(_partitionName, key);
		}
		public void RemoveByTagFromMemCache(string key)
		{
			if (_useMemCache)
				_memoryCache.RemoveByTag(key);
		}
		public void Clear()
		{
			if (_useMemCache)
				_memoryCache.Clear();

			if (_useDbCache)
				_databaseCache.Clear(_partitionName);
		}
		public int Count()
		{
			if (_useDbCache)
				return _databaseCache.Count(_partitionName);

			return _memoryCache.Count();
		}
	}
}
